/* Steve Guo(letsgoustc@gmail.com)
**
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License"); 
** you may not use this file except in compliance with the License. 
** You may obtain a copy of the License at 
**
**     http://www.apache.org/licenses/LICENSE-2.0 
**
** Unless required by applicable law or agreed to in writing, software 
** distributed under the License is distributed on an "AS IS" BASIS, 
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
** See the License for the specific language governing permissions and 
** limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include "bootimg.h"

void usage(char *argv[])
{
    printf("usage: %s <filename>\n", argv[0]);
}

static void *load_file(const char *fn, unsigned *_sz)
{
    char *data;
    int sz;
    int fd;

    data = 0;
    fd = open(fn, O_RDONLY);
    if(fd < 0) return 0;

    sz = lseek(fd, 0, SEEK_END);
    if(sz < 0) goto oops;

    if(lseek(fd, 0, SEEK_SET) != 0) goto oops;

    data = (char*) malloc(sz);
    if(data == 0) goto oops;

    if(read(fd, data, sz) != sz) goto oops;
    close(fd);

    if(_sz) *_sz = sz;
    return data;

oops:
    close(fd);
    if(data != 0) free(data);
    return 0;
}

static void *write_file(const char *fn, char *base, unsigned item_size, unsigned page_size)
{
    int fd;
    unsigned page_mask;
    unsigned padding_count;

    page_mask = page_size - 1;
    if((item_size & page_mask) == 0)
        padding_count = 0;
    else
        padding_count = page_size - (item_size & page_mask);

    fprintf(stderr,"Now generating '%s' ...\n", fn);
 
    fd = open(fn, O_CREAT | O_TRUNC | O_WRONLY, 0644);
    if(fd < 0) {
        fprintf(stderr,"error: could not create '%s'\n",fn);
        return NULL;
    }

    if(write(fd, base, item_size) != item_size){
        fprintf(stderr,"error: write fail '%s'\n",fn);
        unlink(fn);
        return NULL;
    }
    fprintf(stderr,"Done\n");
    return base + item_size + padding_count;
}

int main(int argc, char *argv[])
{
    boot_img_hdr *hdr;
    void *img_data = 0;
    void *kernel_data = 0;
    void *ramdisk_data = 0;
    void *second_data = 0;
    unsigned sz;
    unsigned item_size;
    unsigned page_mask;
    unsigned padding_count;

    if(argc < 2){
        usage(argv);
        exit(-1);
    }

    img_data = load_file(argv[1], &sz);

    hdr = (boot_img_hdr*)img_data;
    if((sz < sizeof(boot_img_hdr)) || (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE) != 0)){
        fprintf(stderr,"The MAGIC KEY is not %s\n", BOOT_MAGIC);
        exit(-1);
    }

    item_size = sizeof(boot_img_hdr);
    if((item_size & page_mask) == 0)
        padding_count = 0;
    else
        padding_count = hdr->page_size - (item_size & page_mask);

    kernel_data = (char*)img_data + item_size + padding_count;
    ramdisk_data = write_file("kernel.img", kernel_data, hdr->kernel_size, hdr->page_size);
    if(!ramdisk_data) exit(-1);
    second_data = write_file("ramdisk.img", ramdisk_data, hdr->ramdisk_size, hdr->page_size);
    if(hdr->second_size > 0) {
        write_file("second.img", second_data, hdr->second_size, hdr->page_size);
    }
    return 0;
}
